#include <std.h>
#include <error.h>
#include <type.h>
#include <dint.h>
#include <memory.h> //Memory allocations for structs
#include <sched.h>
#include <irq.h>
#include <timer.h>
#include <diskfmt.h>
#include <vol.h>
#include <fdcfmt.h>
/**********************Kernel Function File*********************dint.h*/
/*The common driver interface for all drivers*/


static struct reg_drv *head;

static u32 gid;

kdrv dint={
	.global_id=0,
	.name="dint",
	.uptime=0,
	.failures=0,
	.init=init_dint,
	.reset=NULL,
	.deinit=NULL,
	.device_irq=DEVICE_IRQ_UNUSED,
	.device_desc="Driver interface manager.."
};

/*Register a driver structure in the list of registered drivers*/
int register_driver(kdrv *x)
{
	struct reg_drv *temp;
	sane(x==NULL,"register_driver:invalid kdrv");
	add_node_end(struct reg_drv,head,temp);
	temp->driver=x;
	temp->next=NULL;
	get_sched_time(&x->uptime);
	x->failures=0;
	x->global_id=++gid; 
	printk("[%s]",x->name);
	return NULL;
}

/*Start the device and use 3 retries if it fails*/
int start_dev(kdrv *x)
{
	if(!x->init)	{
		error("\nNo init for this driver..");
		return -1;
	}
	x->init();
	return NULL;
}

/*This function is used by a driver to get the functions of another driver it depends on*/
void *get_driver(char *name)
{
	struct reg_drv *temp=head;
	while(temp!=NULL && strcmp(temp->driver->name,name))	{
		temp=temp->next;
	}
	if(temp==NULL)
		return NULL;
	return (void *)temp->driver->device;
}

void *get_device(char *name)
{
	struct reg_drv *temp=head;
	while(temp!=NULL && strcmp(temp->driver->name,name))	{
		temp=temp->next;
	}
	if(temp==NULL)
		return NULL;
	return (void *)temp->driver;
}

int display_registered()
{
	struct reg_drv *temp;
	for(temp=head;temp!=NULL;temp=temp->next)	{
		printk("\nName:%s\tGID:%d\tUp:%dmsec",temp->driver->name,temp->driver->global_id,((u32)temp->driver->uptime)*1000/SYSTEM_SCHEDULE_CLOCK_SPEED);
		printk("\tIRQ:%x",temp->driver->device_irq);
	}
	return NULL;
}

int start_registered()
{
	struct reg_drv *temp;
	for(temp=head;temp!=NULL;temp=temp->next)	{
		start_dev(temp->driver);
	}
	return NULL;
}

int show_driver(char *name)
{
	struct reg_drv *temp=head;
	while(temp!=NULL && strcmp(temp->driver->name,name))	{
		temp=temp->next;
	}
	if(temp==NULL)	{
		error("\nThis driver does not exist.");
		return NULL;
	}
	printk("\nName:%s  GID:%d  Up:%dmsec",temp->driver->name,temp->driver->global_id,((u32)temp->driver->uptime)*1000/SYSTEM_SCHEDULE_CLOCK_SPEED);
	printk("  IRQ:%x",temp->driver->device_irq);
	printk("\n\nDriver Functions:");
	printk("\n%s",temp->driver->device_desc);
	return NULL;
}

#define SCAN 0
volatile int check_irq=SCAN;
volatile u32 last_irq_count;


int device_error(kdrv *driver,const char *msg)
{
	int ret_val;
	sane(!driver,"Driver null");
	ret_val=error("\n[device_error] {%s}",msg);
	driver->failures++;
	return ret_val;
}

extern unsigned long _end;

#define SYS_START 0x100000

struct init_kdrv _null_d={.d=NULL,.sign="bNiN"};
int init_dint()
{
	struct init_kdrv *srch;
	printk("\nInitiating drivers");
	gid=0;
	head=(struct reg_drv *)get_mem(sizeof(struct reg_drv));
	head->driver=&dint;
	head->next=NULL;
	u32 *srch_magic,*dint_magic;	//Search for the init magic number
	dint_magic=_null_d.sign;
	for(srch_magic=(u32 *)SYS_START;srch_magic<(u32 *)_end;srch_magic++)	{
		if(*srch_magic==*dint_magic)	{
			srch=(struct init_kdrv *)((u32)srch_magic-4);
			if(srch->d)	{
				register_driver(srch->d);
				start_dev(srch->d);
			}
		}
	}
	return NULL;
}

int bring_down()
{
	struct reg_drv *temp;
	for(temp=head->next;temp!=NULL;temp=temp->next)	{
		printk("\nStopping:%s",temp->driver->name);
		if(temp->driver->deinit!=NULL)
			temp->driver->deinit();
	}
	return NULL;
}
